package com.linjacy.httpproject.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
//import com.alibaba.excel.metadata.CellData;
//import com.alibaba.excel.metadata.Head;
//import com.alibaba.excel.util.StyleUtil;
//import com.alibaba.excel.write.handler.AbstractCellWriteHandler;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
//import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
//import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
//import com.alibaba.excel.write.metadata.style.WriteCellStyle;
//import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.linjacy.httpproject.excel.CellMergeStrategy;
import com.linjacy.httpproject.excel.DrcpmReportTreeCellStyleStrategy;
import com.linjacy.httpproject.excelListener.UserDataListener;
import com.linjacy.httpproject.exception.SystemErrorException;
import com.linjacy.httpproject.builder.RedisUserBuilder;
import com.linjacy.httpproject.entity.User;
import com.linjacy.httpproject.mapper.UserMapper;
import com.linjacy.httpproject.request.RegisterUserRequest;
import com.linjacy.httpproject.service.UserService;
import com.linjacy.httpproject.thread.UserHolder;
import com.linjacy.httpproject.util.JsonToSelectUtil;
import com.linjacy.httpproject.util.JwtUtil;
import lombok.SneakyThrows;
//import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    //private static final String FILE_HEADER_KEY = "Content-Disposition";
    //private static final String FILE_CONTENT_TYPE = "application/vnd.ms-excel;charset=utf-8";

    @Autowired
    private UserMapper userMapper;

    @Autowired
    RedisTemplate redisTemplate;

    @Override
    @Async("myTaskExecutor")
    public User getUserById(String id) throws SystemErrorException {
        User user = userMapper.getMyUserTest(id);
        //User user = userMapper.selectById(id);
        logger.info("这里登录的用户为{}", UserHolder.getUser());
        //Optional.ofNullable(user).orElseThrow(() -> new SystemErrorException("用户不存在"));
        //模拟超时\
        //for (int i = 0; i < 5; i++) {
        //    analogTimeOut(i);
        //}
        return null;
    }

    void analogTimeOut(int i) {
        try {
            Thread.sleep(5000);
            System.out.println("任务" + i + "执行完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    @Transactional
    public void registerUser(RegisterUserRequest registerUserRequest) {
        User user = new User();
        BeanUtils.copyProperties(registerUserRequest,user);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user.setUserId(UUID.randomUUID().toString().replaceAll("-",""));
        this.userMapper.insert(user);
    }

    @Override
    public String loginUser(RegisterUserRequest registerUserRequest) throws SystemErrorException {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("user_name",registerUserRequest.getUserName()).eq("password",registerUserRequest.getPassword());
        //User user = userMapper.selectOne(wrapper);
        User user = this.getOne(wrapper);
        Optional.ofNullable(user).orElseThrow(() -> new SystemErrorException("用户名或者密码错误"));
        String token = JwtUtil.createToken(user.getUserId(), user.getUserName());
        RedisUserBuilder redisUserBuilder = new RedisUserBuilder();
        Map<String, Object> redisUserHash = redisUserBuilder.buildLoginTime().buildToken(token).buildLoginTimesAndIncrement().build();
        redisTemplate.opsForHash().putAll(user.getUserName() + JwtUtil.REDIS_TOKEN,redisUserHash);
        redisTemplate.expire(user.getUserName() + JwtUtil.REDIS_TOKEN,JwtUtil.EXPIRE_TIME * 2, TimeUnit.MINUTES);
        return token;
    }

    @Override
    public List<User> getUserByRule() {
        return userMapper.selectList(new QueryWrapper<>());
    }

    @Override
    public Map<String, User> getUserList() {
        List<User> userList = userMapper.selectList(new QueryWrapper<>());
        userList.sort(Comparator.comparing(User::getCreateTime));
        return userList.stream().collect(Collectors.toMap(User::getUserId, t -> t, (t1, t2) -> t1));
    }

    @Override
    @SneakyThrows
    public void getExportList(HttpServletResponse response) {
        List<User> exportList = userMapper.selectList(new QueryWrapper<>());
        Map<String, List<User>> listMap = exportList.stream().sorted(Comparator.comparingInt(t-> Integer.parseInt(t.getUserId()))).collect(Collectors.groupingBy(User::getUserGroup));
        Map<String, List<User>> sortMap = new LinkedHashMap(listMap.size());
        listMap.entrySet().stream().sorted(Map.Entry.comparingByValue(Comparator.comparingInt(t-> Integer.parseInt(t.get(0).getUserId()))))
                .forEachOrdered(e -> sortMap.put(e.getKey(), e.getValue()));
        DrcpmReportTreeCellStyleStrategy drcpmReportTreeCellStyleStrategy = new DrcpmReportTreeCellStyleStrategy();
        //单元格合并
        List<CellRangeAddress> cellRangeAddresses = new ArrayList<>();
        //开始要合并的坐标,excel 的坐标也是从0开始
        this.getMergeCell(cellRangeAddresses, 2, sortMap);
        response.setContentType("application/octet-stream");
        String fileName = URLEncoder.encode("用户表格.xlsx", "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        //response.setHeader("Content-disposition",
        //"p_w_upload; filename=" + toUtf8String(excelName));
        //response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", fileName));
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), User.class)
                .registerWriteHandler(new CellMergeStrategy(cellRangeAddresses))
                .registerWriteHandler(drcpmReportTreeCellStyleStrategy)
                .build();
        WriteSheet writeSheet = EasyExcel.writerSheet().needHead(Boolean.TRUE).build();
        AtomicInteger tableNo = new AtomicInteger();
        sortMap.forEach((k,v)->{
            //这里必须指定需要头，table 会继承sheet的配置，sheet 配置了不需要，table 默认也是不需要
            List<List<String>> headList = new ArrayList<>();
            List<String> subHeadList = new ArrayList<>();
            subHeadList.add(k);
            headList.add(subHeadList);
            WriteTable writeTable0 = EasyExcel.writerTable(tableNo.get()).head(headList).needHead(Boolean.TRUE).build();
            // 第一次写入会创建头
            excelWriter.write(sortMap.get(k), writeSheet, writeTable0);
            tableNo.addAndGet(1);
        });
        excelWriter.finish();
        response.getOutputStream().close();
    }

    @Override
    @SneakyThrows
    public void importUserList(MultipartFile file) {
        InputStream inputStream = file.getInputStream();
        EasyExcel.read(inputStream, User.class, new UserDataListener()).sheet().doRead();
    }

    @Override
    public String json2Sql(JSONObject json) throws SystemErrorException {
        return JsonToSelectUtil.parseJson(json);
    }

    //private AbstractCellWriteHandler cellWriteHandler() {
    //    return new AbstractCellWriteHandler(){
    //        @Override
    //        public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean isHead) {
    //            Workbook workbook = writeSheetHolder.getSheet().getWorkbook();
    //            // 这里千万记住 想办法能复用的地方把他缓存起来 一个表格最多创建6W个样式
    //            // 不同单元格尽量传同一个 cellStyle
    //            CellStyle cellStyle = null;
    //            if(isHead != null && isHead) {
    //                WriteCellStyle writeCellStyle = new WriteCellStyle();
    //                writeCellStyle.setBorderBottom(BorderStyle.THIN);
    //                writeCellStyle.setBorderRight(BorderStyle.THIN);
    //                writeCellStyle.setBorderLeft(BorderStyle.THIN);
    //                writeCellStyle.setBorderTop(BorderStyle.THIN);
    //                writeCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
    //                writeCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
    //                writeCellStyle.setFillBackgroundColor(IndexedColors.WHITE1.getIndex());
    //                writeCellStyle.setFillPatternType(FillPatternType.NO_FILL);
    //                WriteFont writeFont = new WriteFont();
    //                writeFont.setBold(true);
    //                writeFont.setFontHeightInPoints((short)11);
    //                writeCellStyle.setWriteFont(writeFont);
    //                cellStyle = StyleUtil.buildHeadCellStyle(workbook,writeCellStyle);
    //            }else {
    //                WriteCellStyle writeCellStyle = new WriteCellStyle();
    //                writeCellStyle.setBorderBottom(BorderStyle.THIN);
    //                writeCellStyle.setBorderRight(BorderStyle.THIN);
    //                writeCellStyle.setBorderLeft(BorderStyle.THIN);
    //                writeCellStyle.setBorderTop(BorderStyle.THIN);
    //                writeCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
    //                writeCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
    //                writeCellStyle.setFillBackgroundColor(IndexedColors.WHITE1.getIndex());
    //                writeCellStyle.setWrapped(true);
    //                WriteFont writeFont = new WriteFont();
    //                writeFont.setBold(false);
    //                writeFont.setFontHeightInPoints((short)11);
    //                writeCellStyle.setWriteFont(writeFont);
    //                cellStyle = StyleUtil.buildContentCellStyle(workbook,writeCellStyle);
    //            }
    //            cell.setCellStyle(cellStyle);
    //        }
    //    };
    //
    //}

    private void getMergeCell(List<CellRangeAddress> cellRangeAddresses, int beginIndex, Map<String, List<User>> itemTypeMap) {
        for (String key : itemTypeMap.keySet()) {
            int size = itemTypeMap.get(key).size();
            cellRangeAddresses.add(new CellRangeAddress(beginIndex, beginIndex, 0, 5));
            beginIndex = beginIndex + 1 + size;
        }
    }
    
    //public static String toUtf8String(String s){
	//    StringBuffer sb = new StringBuffer();
    //    for (int i=0;i<s.length();i++){
    //      char c = s.charAt(i);
    //      if (c >= 0 && c <= 255){
    //          sb.append(c);
    //      }else{
    //        byte[] b;
    //        try {
    //            b = Character.toString(c).getBytes("utf-8");
    //        }
    //        catch (Exception ex) {
    //            System.out.println(ex);
    //            b = new byte[0];
    //        }
    //        for (int j = 0; j < b.length; j++) {
    //            int k = b[j];
    //            if (k < 0) k += 256;
    //            sb.append("%" + Integer.toHexString(k).toUpperCase());
    //        }
    //     }
	//  }
	//  return sb.toString();
    //}
}
